#pragma once

#include<iostream>
#include "epoll_server.hpp"
#include "util.hpp"
#include<vector>
#include<string>

namespace ns_appinterface {

  using namespace ns_epoll;


  int recver(EventItem* item);
  int sender(EventItem* item);
  int errorer(EventItem* item);


  int accepter(EventItem* item)
  {
    std::cout << "get a new link: " << item->sock << std::endl;
    while(true){
      struct sockaddr_in peer;
      socklen_t len = sizeof(peer);
      int sock = accept(item->sock,(struct sockaddr*)&peer,&len);
      if(sock < 0){
        if(errno == EAGAIN || errno == EWOULDBLOCK){
          //说明并没有读取出错，只是底层没有链接了！
           return 0;
        }
        if(errno ==  EINTR){
          //读取的过程被信号打断了
          continue;

        }
        else{
           //真正的出错了
           return -1;
        }
      }
      else{
        //立即将fd设置为非阻塞模式
        ns_comm::SetNonBlock(sock);
        //读取成功了
        EventItem tmp;
        tmp.R = item->R;
        tmp.ManagerCallBack(recver,sender,errorer); 
        Epoller* epoller = item->R;
        ns_comm::SetNonBlock(sock);
        //epoll,设置读事件就绪，而写事件是按需打开！
        epoller->addEven(sock,EPOLLIN|EPOLLET,tmp);
      }

    }
   }
   //0:读取成功
   //-1:读取失败
   int recver_helper(int sock,std::string* out)
   {
     while(true){
        char buffer[128];
        ssize_t size = recv(sock,buffer,sizeof(buffer)-1,0);
        if(size < 0){
          if(errno == EAGAIN || errno == EWOULDBLOCK){
            //循环读取
            return 0;
          }
          else if(errno == EINTR){
            //被信号中断
            continue;
          }
          else{
            //真正出错了；
            return -1;
          }
        }
        else{
          buffer[size] = 0;
          *out += buffer; //将读取的诗句，添加倒inbuffer中
        }
     } 
   }

   int recver(EventItem* item)
   {

      std::cout << "recv event ready:" << item->sock << std::endl;
      //1.需要整体读，非阻塞
      if(recver_helper(item->sock,&item->inbuffer) <0){
        //item->error_handler
        return -1;
      }
      //2.根据发来的数据流，进行包和包之间的分离，放置粘包问题,协议定制
      std::vector<std::string> messages;
      ns_comm::StringUtil::Split(item->inbuffer,&messages,"X");
      //for(auto s : messages){
      //  std::cout << s << std::endl;
      //}
      //3.针对一个一个的报文协议反序列化decode,也是协议定制的一部分
      struct data{
        int x;
        int y;
      };
      //在这里已经拿到了所有的数据报文
      for(auto s : messages){
        struct data d;
        ns_comm::StringUtil::Deserialize(s,&d.x,&d.y);

       // tast t(fd);
        //thread_pool->push(t);

      //  std::cout << d.x << ":" << d.y << std::endl;
         //4.业务处理
         int z = d.x+d.y;
      //5.形成响应报文，序列化转化称为一个字符串encode
        std::string response;
        response += std::to_string(d.x);
        response += "+";
        response += std::to_string(d.y);
        response += "=";
        response += std::to_string(z);

        item->outbuffer += response;
        //5.1 设置响应报文和响应报文之间的分隔符 
        item->outbuffer += "X"; //encode
      }
      //6.写回
      if(!item->outbuffer.empty()) item->R ->EnableReadWrite(item->sock,true,true);
      return 0;
   }

   //0:缓冲区打满，并且写完buffer
   //1.缓冲区打满，下次写入
   //-1:写出错
   //-1:error
   int sender_helper(int sock, std::string& in)
   {
     while(true){
        size_t total = 0;
        ssize_t s = send(sock,in.c_str()+total,in.size()-total,0);
        if(s>0){
          total += s;
            if(total >= in.size()){
              return 0;

           }
        }
        else if(s < 0){
          if(errno == EAGAIN || errno == EWOULDBLOCK){
             //无论是否发生完，inbuffer，都需要将已经发送的数据，全部移出缓冲区
             in.erase(total);
             return 1; //已经将缓冲区打满，不能在写入了
          }
          else if(errno == EINTR){
             //TODO
             continue;
          }
          else{
            return -1;
          }
        }
     }

   }

   int sender(EventItem* item)
   {
     
     int ret = sender_helper(item->sock,item->outbuffer);
     if(ret == 0)
        item->R->EnableReadWrite(item->sock,true,false);
     else if(ret == 1){
       //一般只设置了EPOLLOUT,默认epoll会下次自动触发一次
        item->R->EnableReadWrite(item->sock,true,true);
     }
     else{

     }
      return 0;
   }

    //
    int errorer(EventItem* item)
    {
      close(item->sock);
      item->R->Deserialize(item->sock);
      return 0;
    }
  

  }
}
